package jwt

import (
	"fmt"
	"time"

	"pbj-server/config"

	"github.com/golang-jwt/jwt/v5"
)

// Claims JWT声明结构
type Claims struct {
	UserID   uint   `json:"user_id"`
	Username string `json:"username"`
	Role     string `json:"role"`
	jwt.RegisteredClaims
}

// GenerateToken 生成JWT令牌
func GenerateToken(userID uint, username, role string) (string, error) {
	cfg := config.GetConfig()
	
	// 创建声明
	claims := Claims{
		UserID:   userID,
		Username: username,
		Role:     role,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(cfg.JWT.ExpireTime) * time.Hour)),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
			NotBefore: jwt.NewNumericDate(time.Now()),
			Issuer:    "pbj-server",
			Subject:   fmt.Sprintf("%d", userID),
		},
	}
	
	// 创建令牌
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	
	// 签名令牌
	tokenString, err := token.SignedString([]byte(cfg.JWT.Secret))
	if err != nil {
		return "", fmt.Errorf("签名令牌失败: %v", err)
	}
	
	return tokenString, nil
}

// ValidateToken 验证JWT令牌
func ValidateToken(tokenString string) (*Claims, error) {
	cfg := config.GetConfig()
	
	// 解析令牌
	token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		// 验证签名方法
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		return []byte(cfg.JWT.Secret), nil
	})
	
	if err != nil {
		return nil, fmt.Errorf("解析令牌失败: %v", err)
	}
	
	// 验证令牌
	if !token.Valid {
		return nil, fmt.Errorf("令牌无效")
	}
	
	// 获取声明
	if claims, ok := token.Claims.(*Claims); ok {
		return claims, nil
	}
	
	return nil, fmt.Errorf("无法获取令牌声明")
}

// RefreshToken 刷新JWT令牌
func RefreshToken(tokenString string) (string, error) {
	// 验证原令牌
	claims, err := ValidateToken(tokenString)
	if err != nil {
		return "", err
	}
	
	// 生成新令牌
	return GenerateToken(claims.UserID, claims.Username, claims.Role)
}

// GetTokenExpiration 获取令牌过期时间
func GetTokenExpiration(tokenString string) (time.Time, error) {
	claims, err := ValidateToken(tokenString)
	if err != nil {
		return time.Time{}, err
	}
	
	return claims.ExpiresAt.Time, nil
}

// IsTokenExpired 检查令牌是否过期
func IsTokenExpired(tokenString string) (bool, error) {
	expiration, err := GetTokenExpiration(tokenString)
	if err != nil {
		return true, err
	}
	
	return time.Now().After(expiration), nil
}

// ExtractUserID 从令牌中提取用户ID
func ExtractUserID(tokenString string) (uint, error) {
	claims, err := ValidateToken(tokenString)
	if err != nil {
		return 0, err
	}
	
	return claims.UserID, nil
}

// ExtractUsername 从令牌中提取用户名
func ExtractUsername(tokenString string) (string, error) {
	claims, err := ValidateToken(tokenString)
	if err != nil {
		return "", err
	}
	
	return claims.Username, nil
}

// ExtractRole 从令牌中提取用户角色
func ExtractRole(tokenString string) (string, error) {
	claims, err := ValidateToken(tokenString)
	if err != nil {
		return "", err
	}
	
	return claims.Role, nil
} 